package com.hex.ds.hdtp.core.app.data.transfer.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.common.util.ExcelDownUtil;
import com.hex.ds.hdtp.core.app.data.configuration.dto.excel.DataTransferListExcelDto;
import com.hex.ds.hdtp.core.app.data.transfer.converter.IDataTransferListConverter;
import com.hex.ds.hdtp.core.app.data.transfer.dto.request.DataTransferListRequestDto;
import com.hex.ds.hdtp.core.app.data.transfer.dto.response.DataTransferListResponseDto;
import com.hex.ds.hdtp.core.app.data.transfer.service.IDataTransferListService;
import com.hex.ds.hdtp.core.app.metadata.service.ISourceInfoService;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.data.transfer.po.DataTransferListPo;
import com.hex.ds.hdtp.core.inf.data.transfer.repository.IDataTransferListRepository;
import liquibase.util.file.FilenameUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.hex.bigdata.hbda.utils.FileUtil.upload;

/**
 * @Package: com.hex.ds.hdtp.core.app.data.transfer.service.impl
 * @ClassName DataTransferListService
 * @Description: 数据迁移清单-业务接口实现
 * @Author: wz.li
 * @Date 2023/8/17 20:00
 * @Version v2.0.2
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DataTransferListService implements IDataTransferListService {

    private final IDataTransferListRepository dataTransferListRepository;

    private final IDataTransferListConverter converter;

    private final IPageAndPageDtoConverter pageAndPageDtoConverter;

    private final ISourceInfoService sourceInfoService;


    @Value("${file.path}")
    String filePath;

    /*
     * @Method: queryListByPage <br>
     * @Param: [dataTransferListRequestDto, pageDto] <br>
     * @Return: com.hex.ds.hdtp.core.app.common.page.PageData <br>
     * @Description：分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/17 20:04 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public PageData queryListByPage(DataTransferListRequestDto dataTransferListRequestDto, PageDto pageDto) {
        final Page<DataTransferListPo> pageResult = dataTransferListRepository.queryListByPage(
                converter.toPo(dataTransferListRequestDto), pageAndPageDtoConverter.toPage(pageDto));
        List<DataTransferListResponseDto> responseDtos = converter.toDtoList(pageResult.getData());
        return new PageData(responseDtos, pageResult.getTotal());
    }

    /*
     * @Method: queryListByTaskId <br>
     * @Param: [dataTransferTaskPkId] <br>
     * @Return: java.util.List<com.hex.ds.hdtp.core.app.data.transfer.dto.response.DataTransferListResponseDto> <br>
     * @Description：根据数据迁移任务主键查询对应的迁移清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/22 17:38 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public List<DataTransferListResponseDto> queryListByTaskId(String dataTransferTaskPkId) {
        return converter.toDtoList(dataTransferListRepository.queryListByTaskId(dataTransferTaskPkId));
    }

    /*
     * @Method: queryById <br>
     * @Param: [pkId] <br>
     * @Return: com.hex.ds.hdtp.core.app.data.transfer.dto.response.DataTransferListResponseDto <br>
     * @Description：根据主键查询对应的数据同步清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/22 20:07 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public DataTransferListResponseDto queryById(String pkId) {
        return converter.toDto(dataTransferListRepository.queryById(pkId));
    }

    /*
     * @Method: add <br>
     * @Param: [dataTransferListRequestDto] <br>
     * @Return: void <br>
     * @Description：新增<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/17 20:07 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void add(DataTransferListRequestDto dataTransferListRequestDto) {
        if (dataTransferListRepository.add(converter.toPo(dataTransferListRequestDto)) != 1){
            throw new RuntimeException("新增数据迁移清单失败");
        }
    }

    /*
     * @Method: modifyById <br>
     * @Param: [dataTransferListRequestDto] <br>
     * @Return: void <br>
     * @Description：更新<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/17 20:07 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void modifyById(DataTransferListRequestDto dataTransferListRequestDto) {
        if (dataTransferListRepository.modifyById(converter.toPo(dataTransferListRequestDto)) != 1){
            throw new RuntimeException("更新数据迁移清单失败");
        }
    }

    /*
     * @Method: removeById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/17 20:08 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void removeById(String pkId) {
        if (dataTransferListRepository.removeById(pkId) != 1){
            throw new RuntimeException("删除数据迁移清单失败");
        }
    }


    /**
     * @Method exportDataTransferList
     * @Param pkIds
     * @Return org.springframework.core.io.ByteArrayResource
     * @Description 导出数据迁移清单
     * @Author Yin.Yang
     * @Date 2023/12/21 18:21
     * @Version V1.0
     */
    @Override
    public ByteArrayResource exportDataTransferList(List<String> pkIds) {
        String backUpPath = createSavePath();
        String templateFilePath = "static/DataTransferTemplate.xlsx";
        List<DataTransferListExcelDto> dataTransferListExcelDtos = pkIds.stream()
                .map(this::queryById)
                .filter(Objects::nonNull)
                .map(dto -> converter.toDataTransferListExcelDto(dto, queryConnCode(dto.getSourceConnPkId()), queryConnCode(dto.getTargetConnPkId())))
                .collect(Collectors.toList());
        String saveFilePath = backUpPath + File.separator + "数据迁移清单模板.xlsx";
        ExcelDownUtil.generatedExcel(dataTransferListExcelDtos, templateFilePath, saveFilePath);
        return readBytesFromFile(saveFilePath);
    }

    /**
     * @Method readBytesFromFile
     * @Param filePath
     * @Return org.springframework.core.io.ByteArrayResource
     * @Description 从指定文件路径读取字节数据
     * @Author Yin.Yang
     * @Date 2023/12/22 9:54
     * @Version V1.0
     */
    private ByteArrayResource readBytesFromFile(String filePath) {
        try {
            byte[] bytes = Files.readAllBytes(Paths.get(filePath));
            return new ByteArrayResource(bytes);
        } catch (IOException e) {
            throw new RuntimeException("文件读取失败", e);
        }
    }

    /**
     * @Method queryConnName
     * @Param connPkId
     * @Return java.lang.String
     * @Description 通过数据源PkId查询数据源名称
     * @Author Yin.Yang
     * @Date 2023/12/22 9:52
     * @Version V1.0
     */
    private String queryConnCode(String connPkId) {
        return sourceInfoService.queryByPkId(connPkId).getSourceCode();
    }

    /**
     * @Method createSavePath
     * @Return java.lang.String
     * @Description 创建保存路径
     * @Author Yin.Yang
     * @Date 2023/12/21 17:19
     * @Version V1.0
     */
    private String createSavePath() {
        String savePath = filePath + File.separator + "static/downExcel/DataTransferTask" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false);
        FileUtil.mkdir(savePath);
        return FilenameUtils.separatorsToSystem(savePath);
    }


    /**
     * @Method importDataTransferList
     * @Param multipartFile
     * @Return java.util.List<com.hex.ds.hdtp.core.app.data.configuration.dto.excel.DataTransferListExcelDto>
     * @Description 导入数据迁移清单
     * @Author Yin.Yang
     * @Date 2023/12/22 20:14
     * @Version V1.0
     */
    @Override
    public List<DataTransferListExcelDto> importDataTransferList(MultipartFile multipartFile) {
        String backUpFilePath = backupUploadFile(multipartFile);
        List<DataTransferListExcelDto> dataTransferListExcelDtos = getExcelData(backUpFilePath);
        try {
            dataTransferListExcelDtos.forEach(dto -> {
                if (dto.getSourceConnName() != null && dto.getTargetConnName() != null) {
                    converter.updateDataTransferListExcelDto(dto, queryConnId(dto.getSourceConnName()), queryConnId(dto.getTargetConnName()));
                    dto.setExcelHandleStatus(true);
                } else {
                    throw new RuntimeException("数据源编码为空，无法处理");
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("数据迁移清单导入失败", e);
        }
        return dataTransferListExcelDtos;
    }

    /**
     * @Method queryConnId
     * @Param connPkCode
     * @Return java.lang.String
     * @Description 通过数据源ConCode查询数据源PkId
     * @Author Yin.Yang
     * @Date 2023/12/22 19:31
     * @Version V1.0
     */
    private String queryConnId(String connPkCode) {
        return sourceInfoService.queryBySourceCode(connPkCode).getPkId();
    }

    /**
     * @Method backupUploadFile
     * @Param multipartFile
     * @Return java.lang.String
     * @Description 备份上传的文件
     * @Author Yin.Yang
     * @Date 2023/12/22 15:51
     * @Version V1.0
     */
    private String backupUploadFile(MultipartFile multipartFile) {
        String backUpPath = FilenameUtils.separatorsToSystem(filePath + File.separator + "static/uploadFile/DataTransferTemplate" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false));
        FileUtil.mkdir(backUpPath);
        String updateFilePath = FilenameUtils.separatorsToSystem(backUpPath + File.separator);
        File file = upload(multipartFile, updateFilePath);
        log.debug("上传到服务器的EXCEL文件路径: {}", file.getPath());
        return file.getPath();
    }

    /**
     * @Method getExcelData
     * @Param backUpFilePath
     * @Return java.util.List<com.hex.ds.hdtp.core.app.data.configuration.dto.excel.DataTransferListExcelDto>
     * @Description 读取EXCEL数据
     * @Author Yin.Yang
     * @Date 2023/12/22 15:53
     * @Version V1.0
     */
    private List<DataTransferListExcelDto> getExcelData(String backUpFilePath) {
        ExcelImportResult<DataTransferListExcelDto> convertAfterList = readExcel(backUpFilePath);
        return convertAfterList.getList();
    }

    private ExcelImportResult<DataTransferListExcelDto> readExcel(String backUpFilePath) {
        ImportParams importParams = new ImportParams();
        importParams.setStartRows(1);
        return ExcelImportUtil.importExcelMore(new File(backUpFilePath), DataTransferListExcelDto.class, importParams);
    }
}
